package com.pansoft.openplanet.account.util;

import android.content.Context;

import com.efounder.chat.http.JFCommonRequestManager;
import com.efounder.constant.EnvironmentVariable;
import com.pansoft.openplanet.bean.Account;
import com.pansoft.openplanet.blockchain.EosDataManger;
import com.pansoft.openplanet.blockchain.api.EosChainInfo;
import com.pansoft.openplanet.blockchain.chain.PackedTransaction;
import com.pansoft.openplanet.blockchain.chain.SignedTransaction;
import com.pansoft.openplanet.blockchain.cypto.ec.EosPrivateKey;
import com.pansoft.openplanet.blockchain.ese.Ese;
import com.pansoft.openplanet.blockchain.types.TypeChainId;
import com.pansoft.openplanet.db.AccountDao;
import com.pansoft.openplanet.util.EosNetParamUtil;
import com.pansoft.openplanet.util.EosPublicAndPrivateKeyUtils;
import com.pansoft.openplanet.util.JsonUtil;
import com.pansoft.openplanet.util.TCAccountManager;
import com.utilcode.util.LogUtils;
import com.utilcode.util.TimeUtils;

import org.json.JSONObject;

import java.util.HashMap;
import java.util.Map;

import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import okhttp3.Response;

import static com.efounder.frame.utils.Constants.CHAT_USER_ID;
import static com.pansoft.openplanet.constant.IPAssetsConstant.PERMISSONION;

/**
 * Eos 操作类
 * @author will
 */
public class EosAccountGenerator {

    private static final String BASE_URL = EnvironmentVariable.getProperty("TalkChainUrl", "")
            +"/tcserver/";

    private Context mContext;

    public EosAccountGenerator(Context context) {
        this.mContext = context;
    }

    /**
     * Observable
     *
     * @param ownPriKey
     * @param activePriKey
     * @return
     */
    public static Observable<Map> getObservableByPrivateKey(final String ownPriKey, final String activePriKey) {
        return Observable.create(new ObservableOnSubscribe<Map>() {
            @Override
            public void subscribe(ObservableEmitter<Map> emitter) throws Exception {
                EosPrivateKey mOwnerKey = null;
                EosPrivateKey mActiveKey = null;

                String ownPubKey;
                String activePubKey;
                mActiveKey = new EosPrivateKey(activePriKey);
                mOwnerKey = new EosPrivateKey(ownPriKey);
                //active 公钥
                activePubKey = mActiveKey.getPublicKey().toString();
                //owner 公钥
                ownPubKey = mOwnerKey.getPublicKey().toString();
                //owner 加密私钥
                String secretOwnPriKey = TCAccountManager.encryptByMainPrivKey(ownPriKey);
                //active 加密私钥
                String secretActivePriKey = TCAccountManager.encryptByMainPrivKey(activePriKey);

                Map<String,String> map = new HashMap<>();
                map.put("ownPriKey",ownPriKey);
                map.put("activePriKey",activePriKey);
                map.put("secretOwnPriKey",secretOwnPriKey);
                map.put("secretActivePriKey",secretActivePriKey);
                map.put("ownPubKey",ownPubKey);
                map.put("activePubKey",activePubKey);

                emitter.onNext(map);
                emitter.onComplete();


            }
        });

    }

    /**
     * 创建eos账户，未激活
     * @param walletName 钱包名
     * @param walletAvatar 钱包头像
     * @return account
     */
    public Account generateEosKeysAndAccount(String walletName, String walletAvatar) {

        //分别得到owner和active的公私钥
        EosPrivateKey mOwnerKey = EosPublicAndPrivateKeyUtils.getPrivateKey(2)[0];
        EosPrivateKey mActiveKey = EosPublicAndPrivateKeyUtils.getPrivateKey(2)[1];
        String mAccount_owner_public_key = mOwnerKey.getPublicKey().toString();
        final String mAccount_owner_private_key = mOwnerKey.toString();
        String mAccount_active_public_key = mActiveKey.getPublicKey().toString();
        final String mAccount_active_private_key = mActiveKey.toString();

        //加密保存数据库
        String secretOwnPrivatekey = TCAccountManager.encryptByMainPrivKey(mAccount_owner_private_key);
        String secretActivePrivatekey = TCAccountManager.encryptByMainPrivKey(mAccount_active_private_key);
        //时间戳作为临时的地址
        String randomAddress = String.valueOf(TimeUtils.getNowMills());
        Account account = new Account(randomAddress, walletName, walletAvatar);
        account.setFileName(null);
        account.setImUserId(EnvironmentVariable.getProperty(CHAT_USER_ID));
        account.setSecretPrivateKey(secretOwnPrivatekey);
        account.setPublicKey(mAccount_owner_public_key);
        account.setEosActivePubKey(mAccount_active_public_key);
        account.setEosActivePriKey(secretActivePrivatekey);
        account.setEosAccountNames("");
        account.setMaster(false);
        account.setCurrentShow(false);
        account.setActivate(false);
        account.setEnable(false);
        account.setAccountType(Account.ACCOUNT_TYPE_COMMON);
        //用来存放临时的账号名
//        account.setEosTempName(accountName);
        account.setBlockChainName(EosNetParamUtil.getEosChainName());
        account.setMainAccoutAddress(EnvironmentVariable.getProperty("tc_ethAddress", ""));
        return account;
    }

    /**
     * 同步方式验证账户名是否可用
     * @param TAG tag
     */
    public String verifyAccount(final String TAG, String accountName) {
        try {
            JFCommonRequestManager manager = JFCommonRequestManager.getInstance(mContext);
            HashMap<String, String> params = new HashMap<>();
            params.put("chainId", String.valueOf(EosNetParamUtil.getEosChainId()));
            params.put("accountName", accountName);
            Response response = manager.requestGetBySyn(TAG, BASE_URL +
                    "eos/get_account", params);
            String responseString = response.body().string();
            JSONObject object = new JSONObject(responseString);
            if (object.optString("result").equals("success")) {
                return "fail";
            }
            return "success";
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }


    /**
     * 同步方式获取链上的信息
     * @param TAG tag
     */
    public EosChainInfo getChainInfo(final String TAG) {
        try {
            JFCommonRequestManager manager = JFCommonRequestManager.getInstance(mContext);
            HashMap<String, String> params = new HashMap<>();
            params.put("chainId", String.valueOf(EosNetParamUtil.getEosChainId()));
            Response response = manager.requestGetBySyn(TAG, BASE_URL +
                    "eos/get_info", params);
            String responseString = response.body().string();
            JSONObject object = new JSONObject(responseString);
            if (object.optString("result").equals("success")) {
                //将数据封装为bean
                EosChainInfo mChainInfoBean = (EosChainInfo) JsonUtil
                        .parseStringToBean(object.optJSONObject("data").toString(), EosChainInfo.class);
                LogUtils.d(mChainInfoBean.toString());
                return mChainInfoBean;
            }
            return null;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 转账
     * 组织转账data数据， 生成transaction
     * @param permissionAccount 当前账户名，用来转账，创建账户，需要支付eos的账户
     * @param name 收款方的账户名
     * @param quantity 转账数量， 如"0.2000 EOS", "1.0000 SYS"
     * @param memo 转账备注
     * @param chainInfo chainInfo
     */
    public SignedTransaction parseTransferData(final String permissionAccount, final String name,
                                  final String quantity, final String memo, final EosChainInfo chainInfo) {
        try {
            //组织transfer的data
            String transferData = Ese.parseTransferData(permissionAccount, name, quantity, memo);
            LogUtils.d(transferData);
            EosDataManger eosDataManager = new EosDataManger(mContext, "");
            //生成transaction
            SignedTransaction tx = eosDataManager.createTransferTransaction("eosio.token", "transfer",
                    transferData, new String[]{permissionAccount + "@" + PERMISSONION}, chainInfo);
            return tx;
            //签名
//            signTransaction(TAG, permissionAccount, tx, new TypeChainId(chainInfo.getChain_id()));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 创建新账户
     * 生成newaccount的数据，并生成transaction
     * @param permissionAccount 当前账户名
     * @param name 待创建的账户名
     * @param owner 待创建的账户的owner公钥
     * @param active 待创建的账户的active私钥
     * @param chainInfo chainInfo
     */
    public SignedTransaction parseNewAccountData(final String permissionAccount, final String name,
                                  final String owner, final String active, String stakeNetQuantity,
                                                 String stakeCpuQuantity, final EosChainInfo chainInfo) {
        try {
            //组织newaccount的data
            String newaccountData = Ese.parseAccountData(permissionAccount, name, owner, active);
            LogUtils.d(newaccountData);
            //组织ram的data
            String buyramData = Ese.parseBuyRamData(permissionAccount, name, 4000L);
            LogUtils.d(buyramData);
            //组织delegate的data
            String delegatebwData = Ese.parseDelegateData(permissionAccount, name, stakeNetQuantity,
                    stakeCpuQuantity, 0);
            LogUtils.d(delegatebwData);
            EosDataManger esoDataManager = new EosDataManger(mContext, "");
            //生成transaction
            SignedTransaction tx = esoDataManager.createNewAccountTransaction("eosio",
                    "newaccount", newaccountData, buyramData, delegatebwData,
                    new String[]{permissionAccount + "@" + PERMISSONION}, chainInfo);
            return tx;
            //签名
//            signTransaction(TAG, permissionAccount, tx, new TypeChainId(chainInfo.getChain_id()));
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 对交易进行签名操作
     * @param tx 交易
     * @param permissionAccount 当前的账户名
     * @param chainId 当前区块的id
     */
    public String signTransaction(String permissionAccount, SignedTransaction tx, TypeChainId chainId) {
        try {
            //解密得到当前账户的active私钥
            AccountDao accountDao = new AccountDao(mContext);
            Account account = accountDao.getAccount(permissionAccount);
            String privateKey = account.getEosActivePriKey();
            EosPrivateKey eosPrivateKey = new EosPrivateKey(TCAccountManager.decryptByMainPrivKey(privateKey));
            //签名
            tx.sign(eosPrivateKey, chainId);
            //pack transaction
            String packedTx = new PackedTransaction(tx).toString();
            LogUtils.d(packedTx);
            return packedTx;
            //发送交易
//            pushTransaction(TAG, packedTx);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 发送交易
     * @param TAG tag
     * @param tx 交易
     */
    public String pushTransaction(String TAG,String tx) {
        try {
            JFCommonRequestManager manager = JFCommonRequestManager.getInstance(mContext);
            Response response = manager.requestPostByJSONSyn(TAG, BASE_URL +
                    "eos/push_transaction_body", tx);
            String responseString = response.body().string();
            LogUtils.d(responseString);
            JSONObject object = new JSONObject(responseString);
            if (object.optString("result").equals("success")) {
                JSONObject dataObject = object.optJSONObject("data");
                return dataObject.optString("transactionId");
            }else {
                return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

}
